﻿using Esri.ArcGISRuntime.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Data;
using System.ComponentModel;
using Microsoft.Win32;
using Heroius.Extension;
using Esri.ArcGISRuntime.Mapping.Popups;
using Esri.ArcGISRuntime.UI.Controls;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;

namespace CNEMC_WPF
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            Control = new ControlContext(AppDomain.CurrentDomain.BaseDirectory);

            InitializeComponent();

            Control.LoadStationFile();
            LayoutStations();

            DataContext = this;

            //添加图件浮层
            HolderView.GraphicsOverlays.Add(Overlay);
            //关联地图图件捕捉事件
            HolderView.GeoViewTapped += HolderView_GeoViewTapped;

            dia_load_data = new OpenFileDialog() { Filter = "环境数据文件|china_sites_*.csv|所有CSV文件|*.csv" };

            //初始化等值线绘制控件
            ContourHiddenPanel.Width = (Control.R_E - Control.R_W) * 100;
            ContourHiddenPanel.Height = (Control.R_N - Control.R_S) * 100;
            PlotModel ModelMe = new PlotModel()
            {
                IsLegendVisible = false,
                Padding = new OxyThickness(0),
                PlotAreaBorderThickness = new OxyThickness(0),
                PlotAreaBackground = OxyColors.Transparent,
                PlotMargins = new OxyThickness(0)
            };
            ModelMe.Axes.Add(new LinearAxis()
            {
                Position = AxisPosition.Left,
                IsAxisVisible = false,
                FontSize = 0.0001,
                MaximumPadding = 0,
                MinimumPadding = 0,
                AxislineStyle = LineStyle.None,
                TickStyle = OxyPlot.Axes.TickStyle.None,
                AxislineThickness = 0,
                AxisTickToLabelDistance = 0,
                AxisTitleDistance = 0,
                AxisDistance = 0,
                IsPanEnabled = false,
                IsZoomEnabled = false,
                Minimum = 0,
                Maximum = Control.ContourMeshCount
            });
            ModelMe.Axes.Add(new LinearAxis()
            {
                Position = AxisPosition.Bottom,
                IsAxisVisible = false,
                FontSize = 0.0001,
                MaximumPadding = 0,
                MinimumPadding = 0,
                AxislineStyle = LineStyle.None,
                TickStyle = OxyPlot.Axes.TickStyle.None,
                AxislineThickness = 0,
                AxisTickToLabelDistance = 0,
                AxisTitleDistance = 0,
                AxisDistance = 0,
                IsPanEnabled = false,
                IsZoomEnabled = false,
                Minimum = 0,
                Maximum = Control.ContourMeshCount
            });
            ModelMe.Axes.Add(new LinearColorAxis() { Palette = OxyPalette.Interpolate(256, OxyColors.Green, OxyColors.Yellow, OxyColors.Orange, OxyColors.Red) });
            ContourPlot.Model = ModelMe;
        }

        private void HolderMap_Loaded(object sender, EventArgs e)
        {
            //设置地图的默认范围
            HolderMap.InitialViewpoint = new Viewpoint(new Envelope(Control.R_W, Control.R_N, Control.R_E, Control.R_S, SpatialReferences.Wgs84));
        }

        /// <summary>
        /// 控制上下文的全局实例
        /// </summary>
        public ControlContext Control { get; set; }
        /// <summary>
        /// 图件浮层
        /// </summary>
        private readonly GraphicsOverlay Overlay = new GraphicsOverlay();

        /// <summary>
        /// 基于控制上下文的站点列表向地图添加要素
        /// </summary>
        public void LayoutStations()
        {
            //定义重用的符号
            SimpleMarkerSymbol StationSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, System.Drawing.Color.Red, 6);
            //循环在地图上添加站点图件
            foreach (var s in Control.Stations)
            {
                var g = new Graphic(new MapPoint(s.Longitude, s.Latitude, SpatialReferences.Wgs84), StationSymbol);
                g.Attributes.Add("Code", s.Code); //添加图件属性，用于捕捉时判断关联站点
                Overlay.Graphics.Add(g);
            }

            SetSelectedStation(Control.Stations.First(), Overlay.Graphics[0]);
        }

        //控件动作：在地图上点击站点图标后，将相应站点置于激活状态
        private async void HolderView_GeoViewTapped(object sender, Esri.ArcGISRuntime.UI.Controls.GeoViewInputEventArgs e)
        {
            double tolerance = 10d; // 容差
            int maximumResults = 1; // 返回结果数为1 
            bool onlyReturnPopups = false; // Return more than popups

            try
            {
                // 异步获取识别到的Graphic
                IdentifyGraphicsOverlayResult Result = await HolderView.IdentifyGraphicsOverlayAsync(
                    Overlay,
                    e.Position,
                    tolerance,
                    onlyReturnPopups,
                    maximumResults);

                // 检查结果数量
                if (Result.Graphics.Count > 0)
                {
                    var g = Result.Graphics[0];
                    var code = Result.Graphics[0].Attributes["Code"].ToString();
                    var station = Control.Stations.First(s => s.Code == code);

                    SetSelectedStation(station, g);

                    //MessageBox.Show($"已更新选中站点 {station.Name}，\r\n请在“站点数据”面板中操作");
                }
            }
            catch (Exception ex)
            {
                Control.Log.Add(ex.Message);
            }
        }

        //控件动作：在表格中选择站点，将相应站点置于激活状态
        private void DataGrid_Selected(object sender, RoutedEventArgs e)
        {
            var dg = sender as DataGrid;
            if (dg.SelectedItem != null)
            {
                var station = dg.SelectedItem as StationInfo;
                var g = Overlay.Graphics[Control.Stations.IndexOf(station)];
                SetSelectedStation(station, g);
            }
        }

        public void SetSelectedStation(StationInfo station, Graphic g)
        {
            //移除选中状态
            Overlay.ClearSelection();
            //设置激活站点
            Control.SelectedStation = station;
            //设置选中状态
            g.IsSelected = true;

        }

        //控件动作：清除日志
        private void RefreshLog(object sender, RoutedEventArgs e)
        {
            Control.Log.Clear();
        }

        //控件动作：自定义列表头
        //备注：DataGrid不能自动应用特性，需要在生成列时人为干预
        private void StationList_ColGen(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            //设置列头
            e.Column.Header = StationInfo.GetPropertyDescription(e.PropertyName);
        }

        OpenFileDialog dia_load_data;
        //控件动作：加载数据文件
        private void Load_Data_File(object sender, RoutedEventArgs e)
        {
            if (dia_load_data.ShowDialog() == true)
            {
                Control.LoadDataFile(dia_load_data.FileName);
            }
        }
        //控件动作：清空已经加载的数据
        private void Clear_Loaded_Data(object sender, RoutedEventArgs e)
        {
            Control.Data.Clear();
            Control.LoadedDataFiles.Clear(); //清空数据的同时，清空已加载数据文件列表
        }

        //绘制站点数据曲线
        private void Draw_Line(object sender, RoutedEventArgs e)
        {
            DataYAxis.Title = Control.Diagram.Item.ToString();
            DataLine.ItemsSource = Control.Data.Where(d => (
                d.Time >= Control.Diagram.Start &&
                d.Time <= Control.Diagram.End &&
                d.StationCode == Control.SelectedStation.Code &&
                d.Item == Control.Diagram.Item
            )).Select(dd => new { X = dd.Time, Y = dd.Value });

            //强制曲线重绘
            DataLine.UpdateLayout();
        }

        //多次使用的保持等值线的KML图层
        KmlLayer ContourLayer = null;

        void AddContour()
        {
            if (ContourLayer == null)
            {
                ContourLayer = new KmlLayer(new Uri(Control.KmlFilePath));
                //定义图层的透明度
                ContourLayer.Opacity = 0.5;
            }

            HolderMap.OperationalLayers.Add(ContourLayer);
        }
        void RemoveContour()
        {
            if (ContourLayer != null)
            {
                HolderMap.OperationalLayers.Remove(ContourLayer);
                ContourLayer = null;
            }
        }

        //绘制等值线
        private void Draw_Contour(object sender, RoutedEventArgs e)
        {
            try
            {
                RemoveContour();

                //todo:  图片缓存，避免重复的耗时计算

                //规避非整点的用户设置
                //使用第三方库提供的方法执行新建
                var time = Control.Contour.Time.As(t => new DateTime(t.Year, t.Month, t.Day, t.Hour, 0, 0));

                var disc = Control.Data.Where(d => (d.Time == time && d.Item == Control.Contour.Item)).Select(dd =>
                {
                    var station = Control.Stations.First(s => s.Code == dd.StationCode);
                    return new FittingPoint { X = station.Longitude, Y = station.Latitude, Z = dd.Value };
                });

                Fitting.Calc(disc, Control.ContourMeshCount, out double[,] data);

                ContourPlot.Model.Series.Clear();
                var heat = new HeatMapSeries()
                {
                    X0 = 0, //实际坐标不重要，因为图像没有数轴，且空间位置由KML文件定义
                    X1 = Control.ContourMeshCount - 1,
                    Y0 = 0,
                    Y1 = Control.ContourMeshCount - 1,
                    Interpolate = true,
                    Data = data
                };

                ContourPlot.Model.Series.Add(heat);
                ContourPlot.Model.InvalidatePlot(true);

                //生成图片
                OxyPlot.Wpf.PngExporter.Export(ContourPlot.Model, Control.ContourImagePath,
                    Convert.ToInt32((Control.R_E - Control.R_W) * 100),
                    Convert.ToInt32((Control.R_N - Control.R_S) * 100),
                    OxyColors.Transparent);

                //添加图层
                AddContour();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        //清除等值线
        private void Clear_Contour(object sender, RoutedEventArgs e)
        {
            RemoveContour();
        }
    }
}
